﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.ServiceLocation;
using System.Diagnostics;
using System.Threading;

namespace AzureToolkit.Engine
{
    internal class BatchTransactionalMessageHandler<TMessage> : MessageHandlerBase<TMessage>, IMessageHandler where TMessage : IAzureQueueMessage
    {
        public BatchTransactionalMessageHandler(MessageHandlerSettings settings)
            : base(settings)
        {
        }

        protected override bool Cycle()
        {
            try
            {
                var messages = this.Queue.GetMessages(this.Settings.BatchSize);
                if (messages.Count > 0)
                {
                    var bulkCommand = (IBatchTransactionalCommand<TMessage>)ServiceLocator.Current.GetInstance(Settings.CommandType);

                    var success = false;
                    try
                    {
                        bulkCommand.Run(messages);
                        bulkCommand.Commit();
                        success = true;
                    }
                    catch (Exception ex)
                    {
                        Trace.TraceError(ex.TraceInformation());
                        success = false;
                        foreach (var message in messages)
                        {
                            if (message.DequeueCount > this.Settings.MaxRetries)
                            {
                                this.Queue.ErrorOutMessage(message, ex);
                            }
                        }
                        bulkCommand.Rollback();
                    }
                    finally
                    {
                        foreach (var message in messages)
                        {
                            try
                            {
                                if (success || message.DequeueCount > this.Settings.MaxRetries)
                                {
                                    this.Queue.DeleteMessage(message);
                                }
                            }
                            catch (Exception ex)
                            {
                                Trace.TraceError(ex.TraceInformation());
                            }
                        }

                    }
                }

                Thread.Sleep(this.Settings.IntervalBetweenRuns);
                return messages.Count > 0;
            }
            catch (TimeoutException)
            {
                return true;
            }
        }
    }
}
